package grun

import (
	"bytes"
	"errors"
	"fmt"
	log "github.com/sirupsen/logrus"
	"io"
	"os"
)

const (
	StatusWaiting = "等待中"
	StatusRunning = "运行中"
	StatusEnd     = "已结束"
)

type TaskGraph struct {
	TaskId       string
	Head         *Node
	Logger       *log.Logger
	LogBuffer    *bytes.Buffer
	LogMine      *LogMine
	IsShowStdout bool
	Status       string
	FuncMap      map[string]*NodeFunc
}

func NewTaskGraph() *TaskGraph {
	ft := &TaskGraph{
		TaskId:       "",
		Head:         nil,
		Logger:       log.New(),
		LogBuffer:    &bytes.Buffer{},
		IsShowStdout: false,
		Status:       "",
		FuncMap:      map[string]*NodeFunc{},
	}
	ft.SetOutput(io.MultiWriter(ft.LogBuffer, os.Stdout))
	ft.LogMine = NewLogMine(ft.Logger)
	return ft
}

//func (ft *TaskGraph) Export(IsDetail bool) FuncTaskInfo {
//	//taskLogAll := ""
//	//if IsDetail {
//	//	taskLogAll = ft.GetLog()
//	//}
//	//return fti
//}

func (ft *TaskGraph) SetOutput(ioWriter io.Writer) {
	ft.Logger.SetOutput(ioWriter)
}

func (ft *TaskGraph) RegisterFunc(FuncInfo *NodeFunc) {
	ft.FuncMap[FuncInfo.Name] = FuncInfo
}

func (ft *TaskGraph) GetFunc(FuncName string) (*NodeFunc, error) {
	if funcThis, exist := ft.FuncMap[FuncName]; exist {
		return funcThis, nil
	}
	return &NodeFunc{}, errors.New("func not find")
}

func (ft *TaskGraph) StatusSet(status string) {
	ft.Status = status
}
func (ft *TaskGraph) StatusGet() string {
	return ft.Status
}

// Append 构建任务链
func (ft *TaskGraph) Append(t *Node) {
	if ft.Head == nil {
		ft.Head = &Node{}
	}
	taskCur := ft.Head
	for taskCur.Next != nil {
		taskCur = taskCur.Next
	}
	taskCur.Next = t
}

func (ft *TaskGraph) Get() *Node {
	if ft.Head == nil || ft.Head.Next == nil {
		return nil
	}
	return ft.Head.Next
}

func (ft *TaskGraph) GetLog() string {
	if ft.LogBuffer == nil {
		return ""
	}
	return ft.LogBuffer.String()
}

func (ft *TaskGraph) PrintTaskLine(t *Node) {
	for t != nil {
		log.Errorln(t.Name, t.IsSuccess)
		t = t.Next
	}
}

// Start 执行任务链
func (ft *TaskGraph) Start(t *Node) (bool, error) {
	ft.StatusSet(StatusRunning)
	defer ft.StatusSet(StatusEnd)
	for t != nil {
		if t.LogMine == nil {
			t.LogMine = &LogMine{Logger: ft.Logger}
		}
		ft.LogMine.Println("正在运行任务：", t.Name)
		funcInfo, err := ft.GetFunc(t.FuncName)
		if err != nil {
			ft.LogMine.Errorln(fmt.Sprintf("任务[%v]执行失败，函数不存在：%v", t.Name, t.FuncName))
			t.Error = err
			return false, err
		}
		t.IsSuccess, t.Error = funcInfo.Func(t.Param, t.LogMine)
		if !t.IsSuccess {
			if !t.IsGoOnWhenFail { // 如果设定为true，失败后直接忽略
				return false, t.Error
			}
			if t.TimesReTry == -1 { // 设定-1永远进行重试
				ft.LogMine.Println(fmt.Sprintf("任务[%v]执行失败，剩余重试次数：%v", t.Name, t.TimesReTry))
				continue
			} else if t.TimesReTry > 0 {
				t.TimesReTry--
				ft.LogMine.Println(fmt.Sprintf("任务[%v]执行失败，剩余重试次数：%v", t.Name, t.TimesReTry))
			} else { // 当重试次数减为0后，不再执行
				ft.LogMine.Println(fmt.Sprintf("任务[%v]剩余重试次数为0，执行失败！", t.Name))
				return false, t.Error
			}
		}
		t = t.Next
	}
	ft.LogMine.Println(fmt.Sprintf("所有任务执行完成！"))
	return true, nil
}
